import Header from "./components/Header";
import List from "./components/List";
import Footer from "./components/Footer";
import './App.css'
import { useState } from "react";
import { useEffect } from "react";

/* 
应用组件
*/
export default function App() {

  const [todos, setTodos] = useState(JSON.parse(localStorage.getItem('todos_key')) || [])

  /* 
  didMount / didUpdate / willUnmount
  useEffect(() => {})  didMount + 任何数据更新的didUpdate
  useEffect(() => { // didMount + willUnmount
    return callback
  }, [])
  useEffect(() => {}, [todos]) // didMount + todos更新的didUpdate
  */
  useEffect(() => { // didMount + didUpdate (todos)
    localStorage.setItem('todos_key', JSON.stringify(todos))
  }, [todos])  // 监视了todos


  /* 
  添加todo
  Header传过来什么数据?  title
  */
  const addTodo = (title) => {
    // 根据title创建一个新的todo
    const todo = {id: Date.now(), title, complete: false}
    // 添加到todos
    // 更新todos
    // 问题: 调用setXxx方法更新state时, 不能直接指定原数据, 即使内部数据发生了变化 => 界面不会更新
    // 需要指定一个新的值
    // setTodos(todos) // 传递进去的是一个新的todos吗?  不是, 是同一个, 只是内部多一个todo
    // 需要一个包含todos中所有数据的新数组
    // todos.unshift(todo)
    // console.log('addTodo', todos)
    // setTodos([...todos])
    setTodos([todo, ...todos])

    // todos.unshift(todo)
    // setTodos(todos)  // 组件不会重新调用渲染   内部会进行===的比较, 如果相同不更新
  }

  /* 
  删除指定id对应的todo
  */
  function deleteTodo(id) {
    // 产生一个去除指定id对应的todo的新todos
    const newTodos = todos.filter(todo => todo.id!==id)
    // 更新todos
    setTodos(newTodos)

    // setTodos(todos.filter(todo => todo.id!==id))
  }

  /* 
  反选指定todo: 切换指定todo的complete值
  */
  const toggleTodo = (todo) => {
    // 切换指定todo的complete值
    todo.complete = !todo.complete // 修改的是todos内部的某个todo内部的属性
   
    // 更新todos
    setTodos([...todos])

    // setTodos( todos.map(item => {
    //   if (item===todo) {
    //     return {...item, complete: !item.complete}
    //   }
    //   return item
    // }))
  }

  /* 
  清除已完成的todo
  */
  const clearCompleteTodos = () => {
    setTodos(todos.filter(todo => !todo.complete))
  }

  /* 
  全选/全不选
  */
  const selectAll = (isCheck) => {
    // 将每个todo的complete变为isCheck
    todos.forEach(todo => todo.complete = isCheck)
    setTodos([...todos])
  }


  /* 
  useState(value)
  第一次调用: 在内部生成一个状态数据, 初始值为传入的value, 同时定义一个更新数据并让组件重新render的函数
  后面再调用: 直接取出内部最新的状态数据和更新函数

  App() => {
     count   // 0
      () => {
        count
      }
  }

   App() => {
     count   // 5
     
  }
  */
  // 第一调用: 创建状态数据和更新状态数据的函数, 并将传入的参数为内部状态数据的初始值
  // 后面再次调用: 直接取出内部保存的状态数据和更新函数
  const [count, setCount] = useState(3)
  
  // setCount(count + 1): 将内部状态数据更新为传入的参数, 进行组件更新(重新调用组件函数生成新的vdom => dom diff => 更新真实DOM)

  useEffect(() => {
    setTimeout(() => {
      // setCount(count + 1) // 异步中读取组件函数的状态数据, 可能不是最新的
      setCount((count) => count + 1) // 此时count是最新的
    }, 2000);
  }, [])

  /* 
  内部: 3 => 5
  初始化: 组件函数() { count = 3   () => {count + 1}       }  
  更新: 组件函数() {count=5}
  */
  

  return (
    <div className="todo-container">
      <p>count: {count}</p>
      <button onClick={() => setCount(count + 2)}>更新</button>
      <div className="todo-wrap">
        <Header addTodo={addTodo}/>
        {/* 将todos传递给List */}
        <List todos={todos} deleteTodo={deleteTodo} toggleTodo={toggleTodo}/>
        <Footer todos={todos} clearCompleteTodos={clearCompleteTodos} selectAll={selectAll}/>
      </div>
    </div>
  )
}
